import { StringChain } from "./StringChain";
import { NameParams } from "./types";

/**
 * 创建字符串链式操作实例的便捷函数
 * @param {string} [value=''] - 初始字符串值，默认为空字符串
 * @returns {StringChain} StringChain实例
 * @example
 * // 创建一个空字符串链
 * chain();
 * // 创建一个带初始值的字符串链
 * chain('hello');
 */
export function chain(value: string = ''): StringChain {
    return new StringChain(value);
}

/**
 * 确保值带有指定的单位
 * @param {string | number} value - 要处理的值
 * @param {string} unit - 默认的单位
 * @returns {string} 处理后的带单位的值
 * @throws {Error} 当值类型不是string或number时抛出异常
 * @example
 * // returns '10px'
 * ensureUnit(10, 'px');
 * // returns '10s'
 * ensureUnit('10', 's');
 * // returns '20ms' (字符串类型，直接返回)
 * ensureUnit('20ms', 'ms');
 */
export function ensureUnit(value: string | number, unit: string) {
    if (typeof value === 'number') {
        // 如果是数字类型，添加单位
        return value + unit;
    } else if (typeof value === 'string') {
        // 尝试将字符串转换为数字
        const numValue = Number(value.trim());
        // 检查是否是有效的数字字符串
        if (!isNaN(numValue) && String(numValue) === value.trim()) {
            // 是数字型字符串，添加单位
            return value.trim() + unit;
        } else {
            // 不是数字型字符串，直接返回
            return value;
        }
    }
    // 对于其他类型，抛出异常
    throw new Error(`Invalid type for ensureUnit: expected string or number, got ${typeof value}`);
}

// ltrim、rtrim和trim函数已移至StringChain类内部实现

/**
 * 将CSV字符串转换为记录对象数组
 * @param {string} csvString - CSV格式的字符串，必须包含标题行
 * @param {Object} [options] - 解析选项
 * @param {string} [options.delimiter=','] - 字段分隔符
 * @param {string} [options.quoteChar='"'] - 引号字符
 * @returns {Array<Record<string, string>>} 解析后的记录对象数组
 * @example
 * // 返回 [{name: '张三', age: '20'}, {name: '李四', age: '22'}]
 * csvStringToRecords('name,age\n张三,20\n李四,22');
 */
export function csvStringToRecords(
    csvString: string,
    options: {
        delimiter?: string;
        quoteChar?: string;
    } = {}
): Array<Record<string, string>> {
    const { delimiter = ',', quoteChar = '"' } = options;

    // 使用csvStringToTableArray解析为二维数组
    const tableArray = csvStringToTableArray(csvString, { delimiter, quoteChar });

    if (tableArray.length === 0) {
        return [];
    }

    // 提取标题行并将其余行转换为对象数组
    const headers = tableArray[0];
    const dataRecords = tableArray.slice(1);

    return dataRecords.map(record => {
        const obj: Record<string, string> = {};
        headers.forEach((header, index) => {
            obj[header] = record[index] || '';
        });
        return obj;
    });
}

/**
 * 将CSV字符串转换为二维表数组
 * 
 * @param {string} csvString - CSV格式的字符串
 * @param {Object} [options] - 解析选项
 * @param {string} [options.delimiter=','] - 字段分隔符
 * @param {string} [options.quoteChar='"'] - 引号字符
 * @returns {Array<Array<string>>} 解析后的二维表数组
 * @example
 * // 返回 [['name', 'age'], ['张三', '20'], ['李四', '22']]
 * csvStringToTableArray('name,age\n张三,20\n李四,22');
 */
export function csvStringToTableArray(
    csvString: string,
    options: {
        delimiter?: string;
        quoteChar?: string;
    } = {}
): Array<Array<string>> {
    const { delimiter = ',', quoteChar = '"' } = options;
    const lines = csvString.trim().split(/\r?\n/);
    const records: Array<Array<string>> = [];

    // 解析每一行
    for (let i = 0; i < lines.length; i++) {
        const line = lines[i];
        if (!line.trim()) continue; // 跳过空行

        const fields = [];
        let field = '';
        let inQuotes = false;
        let j = 0;

        while (j < line.length) {
            const char = line[j];

            if (char === quoteChar) {
                if (line[j + 1] === quoteChar) {
                    // 处理双引号转义
                    field += quoteChar;
                    j += 2;
                } else {
                    inQuotes = !inQuotes;
                    j++;
                }
            } else if (char === delimiter && !inQuotes) {
                // 分隔符，且不在引号内
                fields.push(field);
                field = '';
                j++;
            } else {
                field += char;
                j++;
            }
        }

        // 添加最后一个字段
        fields.push(field);
        records.push(fields);
    }

    return records;
}

/**
 * 将参数字符串转换为名称参数对象数组
 * @param {string} paramsStr - 参数字符串，格式为 "name|param1:value1|param2:value2,name2|param3:value3"
 * @returns {Array<NameParams>} 名称参数对象数组
 * @example
 * // 返回 [{name: 'name1', params: {param1: 'value1', param2: 'value2'}}, {name: 'name2', params: {param3: 'value3'}}]
 * toNameParams('name1|param1:value1|param2:value2,name2|param3:value3');
 */
export function toNameParams(paramsStr: string) {
    return paramsStr.split(',').map(part => {
        const trimmedPart = part.trim();
        // 检查是否包含|
        const separatorIndex = trimmedPart.indexOf('|');
        if (separatorIndex === -1) {
            // 不包含|，保持原有逻辑
            return { name: trimmedPart, params: {} } as NameParams;
        } else {
            // 包含|，分割为name和params
            const name = trimmedPart.substring(0, separatorIndex).trim();
            const paramsStr = trimmedPart.substring(separatorIndex + 1).trim();

            // 解析params
            const params: Record<string, string | number | boolean> = {};
            if (paramsStr) {
                paramsStr.split('|').forEach(param => {
                    const paramTrimmed = param.trim();
                    if (paramTrimmed) {
                        const colonIndex = paramTrimmed.indexOf(':');
                        if (colonIndex === -1) {
                            // 没有:，视为标志参数
                            params[paramTrimmed] = true;
                        } else {
                            // 有:，分割为参数名和参数值
                            const paramName = paramTrimmed.substring(0, colonIndex).trim();
                            const paramValue = paramTrimmed.substring(colonIndex + 1).trim();

                            // 尝试转换为数字
                            const numValue = Number(paramValue);
                            params[paramName] = isNaN(numValue) ? paramValue : numValue;
                        }
                    }
                });
            }

            return { name, params } as NameParams;
        }
    });
}